/*
 * Copyright 2011-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0.
 * See `LICENSE` in the project root for license information.
 */

package me.ijleex.jmh.benchmark.counter;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Group;
import org.openjdk.jmh.annotations.GroupThreads;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

import me.ijleex.jmh.benchmark.counter.impl.AdderCounter;
import me.ijleex.jmh.benchmark.counter.impl.AtomicCounter;
import me.ijleex.jmh.benchmark.counter.impl.DirectCounter;
import me.ijleex.jmh.benchmark.counter.impl.DirectVolatileCounter;
import me.ijleex.jmh.benchmark.counter.impl.LockCounter;
import me.ijleex.jmh.benchmark.counter.impl.ReadWriteLockCounter;
import me.ijleex.jmh.benchmark.counter.impl.SemaphoreCounter;
import me.ijleex.jmh.benchmark.counter.impl.StampedCounter;
import me.ijleex.jmh.benchmark.counter.impl.StampedOptimisticCounter;
import me.ijleex.jmh.benchmark.counter.impl.SynchronizedCounter;
import me.ijleex.jmh.benchmark.counter.impl.SynchronizedMethodCounter;

/**
 * CounterBenchmark.
 *
 * @author liym
 * @since 2020-05-27 13:22 新建
 */
@Warmup(iterations = 5)
@Measurement(iterations = 5)
@Fork(1)
@BenchmarkMode(Mode.Throughput)
public class CounterBenchmark {

    @Group("Direct")
    @GroupThreads(60)
    @Benchmark
    public void incrDirect(DirectCounterState state) {
        state.counter.increment();
    }

    @Group("Direct")
    @GroupThreads(40)
    @Benchmark
    public long getDirect(DirectCounterState state) {
        return state.counter.getCount();
    }

    @Group("DirectVolatile")
    @GroupThreads(60)
    @Benchmark
    public void incrDirectVolatile(DirectVolatileCounterState state) {
        state.counter.increment();
    }

    @Group("DirectVolatile")
    @GroupThreads(40)
    @Benchmark
    public long getDirectVolatile(DirectVolatileCounterState state) {
        return state.counter.getCount();
    }

    @Group("Synchronized")
    @GroupThreads(60)
    @Benchmark
    public void incrSynchronized(SynchronizedCounterState state) {
        state.counter.increment();
    }

    @Group("Synchronized")
    @GroupThreads(40)
    @Benchmark
    public long getSynchronized(SynchronizedCounterState state) {
        return state.counter.getCount();
    }

    @Group("SynchronizedMethod")
    @GroupThreads(60)
    @Benchmark
    public void incrSynchronizedMethod(SynchronizedMethodCounterState state) {
        state.counter.increment();
    }

    @Group("SynchronizedMethod")
    @GroupThreads(40)
    @Benchmark
    public long getSynchronizedMethod(SynchronizedMethodCounterState state) {
        return state.counter.getCount();
    }

    @Group("Atomic")
    @GroupThreads(60)
    @Benchmark
    public void incrAtomic(AtomicCounterState state) {
        state.counter.increment();
    }

    @Group("Atomic")
    @GroupThreads(40)
    @Benchmark
    public long getAtomic(AtomicCounterState state) {
        return state.counter.getCount();
    }

    @Group("Adder")
    @GroupThreads(60)
    @Benchmark
    public void incrAdder(AdderCounterState state) {
        state.counter.increment();
    }

    @Group("Adder")
    @GroupThreads(40)
    @Benchmark
    public long getAdder(AdderCounterState state) {
        return state.counter.getCount();
    }

    @Group("LockFair")
    @GroupThreads(60)
    @Benchmark
    public void incrFairLock(FairLockCounterState state) {
        state.counter.increment();
    }

    @Group("LockFair")
    @GroupThreads(40)
    @Benchmark
    public long getFairLock(FairLockCounterState state) {
        return state.counter.getCount();
    }

    @Group("LockNonFair")
    @GroupThreads(60)
    @Benchmark
    public void incrNonFairLock(NonFairLockCounterState state) {
        state.counter.increment();
    }

    @Group("LockNonFair")
    @GroupThreads(40)
    @Benchmark
    public long getNonFairLock(NonFairLockCounterState state) {
        return state.counter.getCount();
    }

    @Group("ReadWriteLockFair")
    @GroupThreads(60)
    @Benchmark
    public void incrFairReadWriteLock(FairReadWriteLockCounterState state) {
        state.counter.increment();
    }

    @Group("ReadWriteLockFair")
    @GroupThreads(40)
    @Benchmark
    public long getFairReadWriteLock(FairReadWriteLockCounterState state) {
        return state.counter.getCount();
    }

    @Group("ReadWriteLockNonFair")
    @GroupThreads(60)
    @Benchmark
    public void incrNonFairReadWriteLock(NonFairReadWriteLockCounterState state) {
        state.counter.increment();
    }

    @Group("ReadWriteLockNonFair")
    @GroupThreads(40)
    @Benchmark
    public long getNonFairReadWriteLock(NonFairReadWriteLockCounterState state) {
        return state.counter.getCount();
    }

    @Group("Stamped")
    @GroupThreads(60)
    @Benchmark
    public void incrStamped(StampedCounterState state) {
        state.counter.increment();
    }

    @Group("Stamped")
    @GroupThreads(40)
    @Benchmark
    public long getStamped(StampedCounterState state) {
        return state.counter.getCount();
    }

    @Group("StampedOptimistic")
    @GroupThreads(60)
    @Benchmark
    public void incrStampedOptimistic(StampedOptimisticCounterState state) {
        state.counter.increment();
    }

    @Group("StampedOptimistic")
    @GroupThreads(40)
    @Benchmark
    public long getStampedOptimistic(StampedOptimisticCounterState state) {
        return state.counter.getCount();
    }

    @Group("SemaphoreFair")
    @GroupThreads(60)
    @Benchmark
    public void incrFairSemaphore(FairSemaphoreCounterState state) {
        state.counter.increment();
    }

    @Group("SemaphoreFair")
    @GroupThreads(40)
    @Benchmark
    public long getFairSemaphore(FairSemaphoreCounterState state) {
        return state.counter.getCount();
    }

    @Group("SemaphoreNonFair")
    @GroupThreads(60)
    @Benchmark
    public void incrNonFairSemaphore(NonFairSemaphoreCounterState state) {
        state.counter.increment();
    }

    @Group("SemaphoreNonFair")
    @GroupThreads(40)
    @Benchmark
    public long getNonFairSemaphore(NonFairSemaphoreCounterState state) {
        return state.counter.getCount();
    }

    // ===

    @State(Scope.Group)
    public static class DirectCounterState {

        private final Counter counter = new DirectCounter();

    }

    @State(Scope.Group)
    public static class DirectVolatileCounterState {

        private final Counter counter = new DirectVolatileCounter();

    }

    @State(Scope.Group)
    public static class SynchronizedCounterState {

        private final Counter counter = new SynchronizedCounter();

    }

    @State(Scope.Group)
    public static class SynchronizedMethodCounterState {

        private final Counter counter = new SynchronizedMethodCounter();

    }

    @State(Scope.Group)
    public static class AtomicCounterState {

        private final Counter counter = new AtomicCounter();

    }

    @State(Scope.Group)
    public static class AdderCounterState {

        private final Counter counter = new AdderCounter();

    }

    @State(Scope.Group)
    public static class FairLockCounterState {

        private final Counter counter = new LockCounter(true);

    }

    @State(Scope.Group)
    public static class NonFairLockCounterState {

        private final Counter counter = new LockCounter(false);

    }

    @State(Scope.Group)
    public static class FairReadWriteLockCounterState {

        private final Counter counter = new ReadWriteLockCounter(true);

    }

    @State(Scope.Group)
    public static class NonFairReadWriteLockCounterState {

        private final Counter counter = new ReadWriteLockCounter(false);

    }

    @State(Scope.Group)
    public static class StampedCounterState {

        private final Counter counter = new StampedCounter();

    }

    @State(Scope.Group)
    public static class StampedOptimisticCounterState {

        private final Counter counter = new StampedOptimisticCounter();

    }

    @State(Scope.Group)
    public static class FairSemaphoreCounterState {

        private final Counter counter = new SemaphoreCounter(true);

    }

    @State(Scope.Group)
    public static class NonFairSemaphoreCounterState {

        private final Counter counter = new SemaphoreCounter(false);

    }

}
